#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author  : Lee
# @File    : dhy_localization_main.py
# @Time    : 2024/1/11 16:22
import os
import json
from views.resource_view.dhy_localization_view import *
from views.matplotlib_view import MplWidget
from util.get_localization_points import *
from views.alert_messagebox_view import *
from util.global_config import global_config
from views.dhy_online_dis_view import DHYOnlineDisView
from views.dhy_connect_row_view import DHYConnectRowView
from views.dhy_threshold_dialog import DHYThresholdDialog
from views.dhy_cut_trajectory_view import DHYCutTrajectoryView
from views.dhy_resource_collection_view import show_dhy_resource_collection_view
from views.dhy_anti_interference_endurance_view import DHYAntiInterferenceEnduranceView


class MainWindow(QtWidgets.QMainWindow, Ui_DHYLocalizationTestView):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)

        self.ABLine.setChecked(True)
        self.angular_text.setEnabled(False)

        # 添加matplotlib视图
        matplotlib_widget = MplWidget(self)
        self.matplotlib_layout.addWidget(matplotlib_widget)
        self.matplotlib_view = matplotlib_widget.qCanvas

        # 数据文件路径
        self.csv_file_path = ""
        self.localization_points_from_csv = list()  # csv文件中原始轨迹数据
        self.cur_localization_points = list()  # 当前参与计算的轨迹数据

        # # 点击菜单栏中“文件” -> “打开csv”
        # self.action_open_csv.triggered.connect(self.select_csv_file)
        # # 点击菜单栏中“文件” -> “重载数据”
        # self.action_reload_csv.triggered.connect(self.load_csv_data)
        # self.action_set_threshold.triggered.connect(self.set_threshold)
        # self.action_connect_row_points.triggered.connect(self.connect_row_test)
        # self.action_online_dis.triggered.connect(self.online_dis_test)
        # self.action_resource_tool.triggered.connect(self.resource_test)
        # self.action_cut_trajectory_points.triggered.connect(self.cut_trajectory_points)
        # self.action_anti_interference_endurance.triggered.connect(self.anti_interference_endurance)

        self.cur_test_type = "ab_line"
        self.virtual_point = list()  # A+测试时，绘制基准线的虚拟B点坐标
        self.test_type_map = {"ab_line": "AB线测试", "a_plus_line": "A+线测试"}

        self.global_config = global_config
        self.end_to_a_dis = self.global_config["end_to_a_dis"]

        # # 监听测试类别
        # self.ABLine.clicked.connect(lambda: self.test_type_changed("ab_line"))
        # self.APlusLine.clicked.connect(lambda: self.test_type_changed("a_plus_line"))

        self.point_a_index = 0   # A点坐标在csv数据中的索引值
        self.point_b_index = -1   # B点坐标在csv数据中的索引值

        self.redraw_line_btn.clicked.connect(lambda: self.redraw_ab_line(True))
        self.reload_data_btn.clicked.connect(self.load_csv_data)
        #  测试设置按钮被点击
        self.test_set_btn.clicked.connect(self.test_set)

    def reset_ab_points_value(self):
        """重置text数值"""
        self.point_a_x_text.setText("")
        self.point_a_y_text.setText("")
        self.point_b_x_text.setText("")
        self.point_b_y_text.setText("")

    def set_point_text(self, point, point_type):
        if point_type == "a":
            self.point_a_x_text.setText(str(round(point[0], 4)))
            self.point_a_y_text.setText(str(round(point[1], 4)))
        elif point_type == "b":
            self.point_b_x_text.setText(str(round(point[0], 4)))
            self.point_b_y_text.setText(str(round(point[1], 4)))

    # @QtCore.pyqtSlot()
    # def load_csv_data(self):
    #     if self.csv_file_path:
    #         # 重置A、B点索引值
    #         self.point_a_index = 0
    #         self.point_b_index = -1
    #
    #         _data = np.loadtxt(self.csv_file_path, delimiter=',')
    #
    #         if _data.shape[-1] > 3:
    #             self.localization_points_from_csv = np.delete(_data, [0], axis=1).tolist()  # 删除第一列
    #         else:
    #             self.localization_points_from_csv = _data[:, [1, 2]].tolist()
    #
    #         self.cur_localization_points = self.localization_points_from_csv
    #
    #         # 重置text数据
    #         self.reset_ab_points_value()
    #
    #         # ab线测试，将轨迹线第一个点设置为A点，最后一个点设置为B点
    #         if self.cur_test_type == "ab_line":
    #             self.matplotlib_view.update_data(self.cur_localization_points, [
    #                 [self.cur_localization_points[self.point_a_index][0],
    #                  self.cur_localization_points[self.point_b_index][0]],
    #                 [self.cur_localization_points[self.point_a_index][1],
    #                  self.cur_localization_points[self.point_b_index][1]]
    #             ])
    #             self.set_point_text(self.cur_localization_points[self.point_a_index], "a")
    #             self.set_point_text(self.cur_localization_points[self.point_b_index], "b")
    #         elif self.cur_test_type == "a_plus_line":
    #             self.set_point_text(self.cur_localization_points[self.point_a_index], "a")
    #             # 设置航向角
    #             self.angular_text.setText(str(round(self.cur_localization_points[self.point_a_index][3], 4)))
    #
    #             # 计算A+线模式下，虚拟B点坐标
    #             self.virtual_point = get_virtual_point(self.cur_localization_points[self.point_a_index],
    #                                                    self.cur_localization_points[-1] if
    #                                                    self.cur_localization_points[0][0] <
    #                                                    self.cur_localization_points[-1][0] else
    #                                                    self.cur_localization_points[0],
    #                                                    self.cur_localization_points[self.point_a_index][3])
    #             # 更新视图
    #             self.matplotlib_view.update_data(self.cur_localization_points,
    #                                              [[self.cur_localization_points[0][0], self.virtual_point[0]],
    #                                               [self.cur_localization_points[0][1], self.virtual_point[1]]])

    # @QtCore.pyqtSlot()
    # def set_threshold(self):
    #     self.dhy_threshold_dialog = DHYThresholdDialog(self.global_config)
    #     self.dhy_threshold_dialog.threshold_value_changed_signal.connect(self.threshold_value_changed)
    #     self.dhy_threshold_dialog.exec_()

    # @QtCore.pyqtSlot()
    # def connect_row_test(self):
    #     self.dhy_connect_row_view = DHYConnectRowView()
    #     self.dhy_connect_row_view.show()

    # @QtCore.pyqtSlot()
    # def resource_test(self):
    #     options = QtWidgets.QFileDialog.Options()
    #     options |= QtWidgets.QFileDialog.DontUseNativeDialog
    #     txt_files_path, _ = QtWidgets.QFileDialog.getOpenFileNames(None, "QFileDialog.getOpenFileName()", "",
    #                                                                "CSV Files (*.txt)", options=options)
    #     if txt_files_path:
    #         # 将多个文件升序排列，保证多个文件中时间顺序为升序
    #         txt_files_path.sort()
    #         show_dhy_resource_collection_view(txt_files_path)

    # @QtCore.pyqtSlot()
    # def cut_trajectory_points(self):
    #     self.cut_trajectory_points_view = DHYCutTrajectoryView()
    #     self.cut_trajectory_points_view.show()
    #
    # @QtCore.pyqtSlot()
    # def anti_interference_endurance(self):
    #     self.anti_interference_endurance_view = DHYAntiInterferenceEnduranceView()
    #     self.anti_interference_endurance_view.show()

    # @QtCore.pyqtSlot()
    # def online_dis_test(self):
    #     self.online_dis_test_view = DHYOnlineDisView()
    #     self.online_dis_test_view.show()

    # 点击坐标点，设置A、B点坐标
    def get_clicked_index(self, point_index):
        if len(self.cur_localization_points) != len(self.localization_points_from_csv):
            QMessageBox.warning(None, "Warning", "当前图标展示数据与csv文件中不一致，请重载数据后再进行操作！")
        else:
            point = self.cur_localization_points[point_index]
            _title = "设置A、B点坐标"
            _text = "选中的定位点坐标为：\n    x: {}\n    y: {}".format(point[0], point[1])
            _btn_text_list = ["设为A点", "设为B点", "取消"]
            if self.cur_test_type == "a_plus_line":
                _title = "设置A点"
                _btn_text_list = ["设为A点", "取消"]
                _dis = get_distance_of_two_point(point,
                                                 [float(self.point_a_x_text.text()), float(self.point_a_y_text.text())])
                _text = _text + "\n当前点与A点距离为: {}m".format(round(_dis, 2))
            clicked_btn = show_message_box(_title, _text, _btn_text_list)

            if clicked_btn == "设为A点":
                self.point_a_index = point_index
                self.set_point_text(point, "a")
                if self.angular_text.isEnabled():
                    self.angular_text.setText(str(round(point[3], 4)))
                self.redraw_ab_line()
            elif clicked_btn == "设为B点":
                self.point_b_index = point_index
                self.set_point_text(point, "b")
                self.redraw_ab_line()
            elif clicked_btn == "取消":
                print("点击了取消按钮...")

    # 获取参与计算的定位点
    def get_calc_points(self):
        # AB线测试，需要获取A、B点坐标、全量轨迹数据
        if self.cur_test_type == "ab_line":
            _point_a = [float(self.point_a_x_text.text()), float(self.point_a_y_text.text())]
            _point_b = [float(self.point_b_x_text.text()), float(self.point_b_y_text.text())]
            return _point_a, _point_b, self.localization_points_from_csv
        elif self.cur_test_type == "a_plus_line":
            # A+线，需要获取A、虚拟B点坐标，计算A点100米的点为终止线，全量数据中截取A-终止线之间的数据参与计算
            _point_a = [float(self.point_a_x_text.text()), float(self.point_a_y_text.text())]
            _end_index = -1
            for index in range(self.point_a_index, len(self.localization_points_from_csv)):
                if get_distance_of_two_point(self.localization_points_from_csv[self.point_a_index],
                                             self.localization_points_from_csv[index]) >= self.end_to_a_dis:
                    _end_index = index
                    break
            _calc_points = self.localization_points_from_csv[self.point_a_index:_end_index]
            _point_b = get_intersection(_point_a, self.virtual_point, _calc_points[-1])
            return _point_a, _point_b, _calc_points

    @QtCore.pyqtSlot()
    def redraw_ab_line(self, is_slot=False):
        _point_a = self.cur_localization_points[self.point_a_index]
        _point_b = self.cur_localization_points[self.point_b_index]
        _angle = self.cur_localization_points[self.point_a_index][3]
        if is_slot:
            _point_a = [float(self.point_a_x_text.text()), float(self.point_a_y_text.text())]
            if self.cur_test_type == "ab_line":
                _point_b = [float(self.point_b_x_text.text()), float(self.point_b_y_text.text())]
            else:
                _angle = float(self.angular_text.text())
        if self.cur_test_type == "a_plus_line":
            self.virtual_point = get_virtual_point(_point_a, self.cur_localization_points[-1] if
            self.cur_localization_points[0][0] > self.cur_localization_points[-1][0] else
            self.cur_localization_points[0], _angle)
            _point_b = self.virtual_point
        self.matplotlib_view.update_a_b_line([[_point_a[0], _point_b[0]], [_point_a[1], _point_b[1]]])

    # @QtCore.pyqtSlot()
    # def select_csv_file(self):
    #     options = QtWidgets.QFileDialog.Options()
    #     options |= QtWidgets.QFileDialog.DontUseNativeDialog
    #     self.csv_file_path, _ = QtWidgets.QFileDialog.getOpenFileName(None, "QFileDialog.getOpenFileName()", "",
    #                                                                   "CSV Files (*.csv)", options=options)
    #     self.load_csv_data()

    # @QtCore.pyqtSlot()
    # def test_type_changed(self, test_type):
    #     if self.cur_test_type != test_type:
    #         _title = "更改测试类型"
    #         _text = "更改后将重新加载数据，确定将【{}】更改为【{}】？".format(self.test_type_map[self.cur_test_type],
    #                                                     self.test_type_map[test_type])
    #         _btn_text_list = ["确定", "取消"]
    #         clicked_btn = show_message_box(_title, _text, _btn_text_list)
    #         if clicked_btn == "确定":
    #             self.cur_test_type = test_type
    #             self.load_csv_data()
    #         else:
    #             print("更改测试类别时，点击了取消按钮...")
    #             if self.cur_test_type == "ab_line":
    #                 self.ABLine.setChecked(True)
    #             else:
    #                 self.APlusLine.setChecked(True)
    #
    #     if self.cur_test_type == "a_plus_line":
    #         self.angular_text.setEnabled(True)
    #         self.point_b_x_text.setEnabled(False)
    #         self.point_b_y_text.setEnabled(False)
    #     else:
    #         self.angular_text.setEnabled(False)
    #         self.point_b_x_text.setEnabled(True)
    #         self.point_b_y_text.setEnabled(True)

    @QtCore.pyqtSlot()
    def test_set(self):
        if not self.csv_file_path:
            QMessageBox.warning(None, "Warning", "设置前请先选择CSV文件！")
            return

        if self.cur_test_type == "ab_line":
            self.dhy_ab_dialog = DHYABDialog(self.global_config)
            self.dhy_ab_dialog.set_ab_points([
                [self.point_a_x_text.text(), self.point_a_y_text.text()],
                [self.point_b_x_text.text(), self.point_b_y_text.text()]
            ])
            # 重绘参考线
            self.dhy_ab_dialog.redraw_ab_line_signal.connect(self.ab_dialog_redraw_ab_line_signal)
            # 开始测试 & 导出结果
            self.dhy_ab_dialog.start_test_signal.connect(self.ab_dialog_start_test_signal)
            self.dhy_ab_dialog.exec_()
        elif self.cur_test_type == "a_plus_line":
            self.dhy_a_plus_dialog = DHYAPlusDialog(self.global_config)
            self.dhy_a_plus_dialog.set_text_values([self.point_a_x_text.text(), self.point_a_y_text.text()],
                                                   self.angular_text.text())
            # 重绘参考线
            self.dhy_a_plus_dialog.redraw_a_plus_line_signal.connect(self.a_plus_dialog_redraw_ab_line_signal)
            # 开始测试 & 导出结果
            self.dhy_a_plus_dialog.start_test_signal.connect(self.a_plus_dialog_start_test_signal)
            self.dhy_a_plus_dialog.exec_()

    def start_test(self, point_a, point_b, calc_points, online_dis, start_line_dis=0):
        _p_obj = GetLocalizationPoints((point_a, point_b), start_line_dis, calc_points,
                                       self.global_config["aver_count"])
        test_res = _p_obj.start_calc(self.cur_test_type)

        _online_index = 1
        for index in range(self.point_a_index, len(self.localization_points_from_csv)):
            if get_distance_of_two_point(
                    self.localization_points_from_csv[self.point_a_index], self.localization_points_from_csv[index]
            ) >= online_dis:
                _online_index = index
                break
        if _online_index == 1:
            QMessageBox.warning(None, "Warning", "请确认行驶轨迹的长度大于设定的上线距离！")
        else:
            _max_dis = 0
            _p_obj = GetLocalizationPoints((point_a, point_b), 0, self.localization_points_from_csv[_online_index:])
            _max_online_dis = _p_obj.calc_max_online_dis()
            test_res["上线距离结果(cm)"] = _max_online_dis
        return test_res

    # -------------------------------  AB线Dialog监听事件  -------------------------------
    def ab_dialog_redraw_ab_line_signal(self, redraw_ab_line_signal_values):
        _points = redraw_ab_line_signal_values["points"]
        self.set_point_text(_points[0], "a")
        self.set_point_text(_points[1], "b")
        self.redraw_ab_line(is_slot=redraw_ab_line_signal_values["is_slot"])

    def ab_dialog_start_test_signal(self, start_test_params):
        self.ab_dialog_redraw_ab_line_signal(start_test_params)
        _point_a, _point_b, _calc_points = self.get_calc_points()
        test_res = self.start_test(_point_a, _point_b, _calc_points, float(start_test_params["online_dis"]),
                                   float(start_test_params["start_line_dis"]))
        if start_test_params["is_export"]:
            # 创建一个对话框让用户选择导出路径
            directory = QtWidgets.QFileDialog.\
                getExistingDirectory(None, "选择导出目录", "",
                                     QtWidgets.QFileDialog.ShowDirsOnly | QtWidgets.QFileDialog.DontResolveSymlinks)
            self.export_res(directory, test_res)
        else:
            _format_text = format_message_text(test_res)
            QMessageBox.information(None, "测试结果", _format_text, QMessageBox.Ok)

    # -------------------------------  A+线Dialog监听事件  -------------------------------
    def a_plus_dialog_redraw_ab_line_signal(self, redraw_a_plus_line_signal_values):
        self.set_point_text(redraw_a_plus_line_signal_values["points"], "a")
        self.angular_text.setText(redraw_a_plus_line_signal_values["angular"])
        self.redraw_ab_line(is_slot=redraw_a_plus_line_signal_values["is_slot"])

    def a_plus_dialog_start_test_signal(self, start_test_params):
        self.a_plus_dialog_redraw_ab_line_signal(start_test_params)
        _point_a, _point_b, _calc_points = self.get_calc_points()
        test_res = self.start_test(_point_a, _point_b, _calc_points, float(start_test_params["online_dis"]))
        if start_test_params["is_export"]:
            # 创建一个对话框让用户选择导出路径
            directory = QtWidgets.QFileDialog.\
                getExistingDirectory(None, "选择导出目录", "",
                                     QtWidgets.QFileDialog.ShowDirsOnly | QtWidgets.QFileDialog.DontResolveSymlinks)
            self.export_res(directory, test_res)
        else:
            _format_text = format_message_text(test_res)
            QMessageBox.information(None, "测试结果", _format_text, QMessageBox.Ok)

    # -------------------------------  修改阈值监听事件  -------------------------------
    def threshold_value_changed(self, threshold_value):
        self.global_config = threshold_value
        self.dhy_threshold_dialog.close()

    def export_res(self, directory, test_res):
        csv_file_name = os.path.basename(self.csv_file_path)[:-4]
        with open(os.path.join(directory, csv_file_name + "_res.json"), 'w', encoding='utf-8') as f_obj:
            json.dump({
                    "测试类型": self.test_type_map[self.cur_test_type],
                    "测试结果": test_res
                }, f_obj, ensure_ascii=False)
        if hasattr(self, "dhy_a_plus_dialog"):
            self.dhy_a_plus_dialog.close()
        if hasattr(self, "dhy_ab_dialog"):
            self.dhy_ab_dialog.close()
